package com.mall.seckill.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.mall.common.response.CommonResponse;
import com.mall.constant.enums.CommonStatus;
import com.mall.constant.strings.ConstantStrings;
import com.mall.constant.strings.ErrorMsg;
import com.mall.constant.strings.MapMsg;
import com.mall.constant.strings.SuccessMsg;
import com.mall.entity.TbCar;
import com.mall.entity.TbGoodsEvaluate;
import com.mall.entity.TbItmeSpec;
import com.mall.entity.TbSeckillItem;
import com.mall.seckill.mapper.SeckillItemMapper;
import com.mall.seckill.mq.Producer;
import com.mall.seckill.service.ISeckillItemService;
import com.mall.seckill.entity.vo.SeckillItemVo;
import com.mall.seckill.service.SeckillOrderService;
import com.mall.utils.IdWorker;
import org.redisson.Redisson;
import org.redisson.api.RLock;
import org.redisson.api.RMap;
import org.redisson.api.RReadWriteLock;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 秒杀商品服务impl
 * created with IntelliJ IDEA
 *
 * @author ASUS
 * @Auther: W
 * @Date: 2021/07/18/9:52
 * Other:
 */
@Service
public class SeckillItemServiceImpl implements ISeckillItemService {

    @Autowired
    private SeckillItemMapper seckillItemMapper;

    @Autowired
    private Redisson redisson;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private Producer producer;



    @Override
    public PageInfo findAll(TbSeckillItem seckillItem, int pageNum, int pageSize) {
        PageHelper.startPage(pageNum, pageSize);
        List<TbSeckillItem> list = seckillItemMapper.findAll(seckillItem);
        PageInfo<TbSeckillItem> pageInfo = new PageInfo<>(list);
        return pageInfo;
    }

    @Override
    public List<SeckillItemVo> findSeckillList(String time) {
        if (time==null){
            time = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
        }
        List<SeckillItemVo> list = seckillItemMapper.findSeckillList(time);
        String key = "seckillProduct";
        list.stream().forEach(item->{
            redisTemplate.opsForValue().set("seckillProduct:" + item.getId(),item.getSeckillNum());
        });
        return list;
    }

    @Override
    public  void addSeckillToRedis(){
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        //simpleDateFormat.format(new Date())
        List<SeckillItemVo> list = seckillItemMapper.findSeckillList("2021-08-07 16:00:00");
        Map<Long, SeckillItemVo> maps = list.stream().collect(Collectors
                .toMap(SeckillItemVo::getId, Function.identity(), (key1, key2) -> key2));
        RMap<Object, Object> seckillItemMap = redisson.getMap(MapMsg.MALL_REDIS_MAP);
        RLock seckillItemMapLock = seckillItemMap.getLock(MapMsg.MALL_REDIS_MAP);
//        redisTemplate.opsForValue().set("KEY"+"uid"+"KEY"+"gid","",10,TimeUnit.SECONDS);
//        redisTemplate.delete("123456789");
        try{
            seckillItemMapLock.lock(5, TimeUnit.SECONDS);
            seckillItemMap.clear();
            seckillItemMap.putAll(maps);
        }finally {
            seckillItemMapLock.unlock();
        }
    }

    @Override
    public CommonResponse<Object> doSeckill(Long uid, Long itemId) {
        //判单uid和gid是否为空
        if (uid==null || itemId==null){
            return new CommonResponse<>(CommonStatus.UNVALID.getCode(), ErrorMsg.ERROR_PARAM_404);
        }
        //通过map名获取秒杀商品的RMap对象
        RMap<Object, Object> seckillItemMap = redisson.getMap(MapMsg.MALL_REDIS_MAP);
        //通过map名获取用户的的RMap对象
        RMap<Object, Object> userMap = redisson.getMap(MapMsg.USER_REDIS_MAP+":"+uid);
        //商品购买次数
        AtomicInteger atomicInteger = new AtomicInteger(0);
        //获取userMap的锁
//        RLock userMapLock = userMap.getLock(itemId);
//        //获取秒杀商品map对象的读写锁,用户id作为key
//        RLock seckillItemMapLock = seckillItemMap.getLock(uid);
        RLock lock = redisson.getLock(itemId.toString());
        //写锁操作数据，修改商品售出数量及状态，更新用户购买商品次数记录
        try {
            //对redis中的数据上锁
//                seckillItemMapLock.lock(5, TimeUnit.SECONDS);
//                userMapLock.lock(5, TimeUnit.SECONDS);
            lock.lock(5, TimeUnit.SECONDS);
            SeckillItemVo seckillItemVo=(SeckillItemVo)seckillItemMap.get(itemId);
            Object userByCountObject =userMap.get(seckillItemVo.getGid());
            //通过秒杀商品id获取对象
            if (userByCountObject!=null){
                if ((int)userByCountObject>=seckillItemVo.getCount()){
                    //返回信息
                    System.out.println("秒杀次数已用尽");
                    return new CommonResponse<>(CommonStatus.UNVALID.getCode(), ErrorMsg.ERROR_AGAIN_404);
                }
                atomicInteger.set((int)userMap.get(seckillItemVo.getGid()));
            }
            //如果准备秒杀的商品状态为已结束则返回
            if (ConstantStrings.FINISH_STATUS.equals(seckillItemVo.getStatus())){
                return new CommonResponse<>(CommonStatus.UNVALID.getCode(), ErrorMsg.ERROR_NUM_404);
                //如果准备秒杀的商品售出数量大于限购数量
            }else if (seckillItemVo.getSaleNum()>=seckillItemVo.getSeckillNum()){
                //设置秒杀状态为已结束
                seckillItemVo.setStatus(ConstantStrings.FINISH_STATUS);
                //将商品对象更新到map
                seckillItemMap.put(itemId,seckillItemVo);
                System.out.println("秒杀状态：售空");
                System.out.println(seckillItemVo);
                //返回结果
                return new CommonResponse<>(CommonStatus.UNVALID.getCode(), ErrorMsg.ERROR_NUM_404);
            }
            //购买成功，销量+1
            seckillItemVo.setSaleNum(seckillItemVo.getSaleNum()+1);
            //设置商品已出售百分比
            seckillItemVo.setRate((double)seckillItemVo.getSaleNum()/(double)seckillItemVo.getSeckillNum());
            seckillItemMap.put(itemId,seckillItemVo);
            //将用户商品购买次数map中该用户对该商品的购买次数+1
            userMap.put(seckillItemVo.getGid(),atomicInteger.incrementAndGet());
            //
            //消息队列执行订单逻辑
            Map<Object,Object> map = new HashMap<>();
            map.put("itemId",itemId);
            map.put("uid",uid);
            producer.proOrder(JSONObject.toJSONString(map));
            //
            //将商品对象更新到map
            System.out.println("销量："+seckillItemVo.getSaleNum());
            System.out.println("用户："+uid+"--->购买次数："+atomicInteger.get());
        }finally {
            lock.unlock();
//            userMapLock.unlock();
//            seckillItemMapLock.unlock();
        }
        //返回结果
        return new CommonResponse<>(CommonStatus.VALID.getCode(), SuccessMsg.SUCCESS_CODE_200);
    }

    @Override
    public List<TbGoodsEvaluate> findGoodsEvaluate(Integer id) {
        return seckillItemMapper.findGoodsEvaluate(id);
    }

    @Override
    public CommonResponse addCar(Integer uid, Integer id) {
        //获取到该商品信息
        TbItmeSpec itmeSpec = seckillItemMapper.findGoodsBySeckillItemId(id);
        //查询购物车中是否有该商品信息
        TbCar car = seckillItemMapper.findCarByUidandGoodsId(uid,itmeSpec.getGoodsId());
        if (car!=null){
            return new CommonResponse(CommonStatus.UNVALID.getCode(), ErrorMsg.ERROR_ADD_AGAIN_404);
        }else{
            TbCar tbCar = new TbCar();
            tbCar.setUserId(uid);
            tbCar.setGoodsId(itmeSpec.getGoodsId());
            tbCar.setPrice(itmeSpec.getPrice());
            tbCar.setBuyNum(1);
            tbCar.setTotal(new BigDecimal(tbCar.getPrice().doubleValue()*tbCar.getBuyNum().doubleValue()));
            tbCar.setStatus("0");
            tbCar.setCreateTime(new Date());
            seckillItemMapper.addCar(tbCar);
            return new CommonResponse(CommonStatus.VALID.getCode(), SuccessMsg.SUCCESS_CODE_200);
        }
    }

    @Override
    public Boolean addSeckillItem(SeckillItemVo seckillItemVo) {
        List<Long> itemSpecIdList = JSON.parseArray(seckillItemVo.getItemSpecIdJson(), Long.class);
        try{
            itemSpecIdList.stream().forEach(itemSpecId->{
                seckillItemVo.setId(new IdWorker().nextId());
                seckillItemVo.setItemSpecId(itemSpecId);
                seckillItemMapper.addSeckillItem(seckillItemVo);
            });
        }catch (Exception e){
            return false;
        }
        return true;
    }

    @Override
    public Boolean update(TbSeckillItem tbSeckillItem) {
        return seckillItemMapper.update(tbSeckillItem);
    }

    @Override
    public TbSeckillItem findById(Long id) {
        return seckillItemMapper.findOne(id);
    }

}